package com.xsjiong.jaript;

import com.xsjiong.jaript.lexer.JSymbols;

import java.util.HashSet;
import java.util.Set;

public abstract class JOperator {
	private static Set<JOperator> S = new HashSet<>();

	public static JOperator getOperator(Object a) {
		return getOperator(a.getClass());
	}

	public static JOperator getOperator(Class<?> a) {
		JOperator r = null;
		for (JOperator op : S) {
			if (op.C.isAssignableFrom(a)) {
				r = op;
				break;
			}
		}
		return r;
	}

	Class C;

	private JOperator(Class c) {
		this.C = c;
	}

	public abstract Object calc(Object a, Object b, byte op);

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof JOperator)) return false;
		JOperator q = (JOperator) obj;
		return (q.C == C);
	}

	/*@Override
	 public int hashCode() {
	 return (C1.hashCode() * 2 + C2.hashCode()) * B + (Swapable ? Integer.MIN_VALUE : 0);
	 }*/

	public static final byte getPriority(byte b) {
		switch (b) {
			case JSymbols.SelfBitwiseAnd:
			case JSymbols.SelfBitwiseOr:
			case JSymbols.SelfShiftBitsLeft:
			case JSymbols.SelfShiftBitsRight:
			case JSymbols.SelfUnsignedShiftBitsRight:
				return 1;
			case JSymbols.Assignment:
			case JSymbols.SelfPlus:
			case JSymbols.SelfMinus:
			case JSymbols.SelfMultiplication:
			case JSymbols.SelfDivision:
			case JSymbols.SelfModulo:
				return 2;
			// TODO 三目运算符
			case JSymbols.Or:
				return 4;
			case JSymbols.And:
				return 5;
			case JSymbols.BitwiseOr:
				return 6;
			case JSymbols.BitwiseXor:
				return 7;
			case JSymbols.BitwiseAnd:
				return 8;
			case JSymbols.Equal:
			case JSymbols.NotEqualTo:
				return 9;
			case JSymbols.Greater:
			case JSymbols.GreaterOrEqual:
			case JSymbols.Less:
			case JSymbols.LessOrEqual:
				return 10;
			case JSymbols.ShiftBitsLeft:
			case JSymbols.ShiftBitsRight:
			case JSymbols.UnsignedShiftBitsRight:
				return 11;
			case JSymbols.Plus:
			case JSymbols.Minus:
				return 12;
			case JSymbols.Multiplication:
			case JSymbols.Division:
			case JSymbols.Modulo:
				return 13;
			case JSymbols.Increase:
			case JSymbols.Decrease:
			case JSymbols.Not:
				return 14;
			case JSymbols.LeftParenthesis:
			case JSymbols.LeftSquareBracket:
				return 15;
		}
		return -1;
	}

	static {
		S.add(new JOperator(Number.class) {
			@Override
			public Object calc(Object aa, Object bb, byte op) {
				if (bb == null) throw new IllegalArgumentException("没有运算可以适用于 Number 与 null 之间");
				Number a = (Number) aa;
				if (bb instanceof Number) {
					Number b = (Number) bb;
					switch (op) {
						case JSymbols.Plus:
							if (a instanceof Double || b instanceof Double)
								return a.doubleValue() + b.doubleValue();
							else if (a instanceof Float || b instanceof Float)
								return a.floatValue() + b.floatValue();
							else if (a instanceof Long || b instanceof Long)
								return a.longValue() + b.longValue();
							else
								return a.intValue() + b.intValue();
						case JSymbols.Minus:
							if (a instanceof Double || b instanceof Double)
								return a.doubleValue() - b.doubleValue();
							else if (a instanceof Float || b instanceof Float)
								return a.floatValue() - b.floatValue();
							else if (a instanceof Long || b instanceof Long)
								return a.longValue() - b.longValue();
							else
								return a.intValue() - b.intValue();
						case JSymbols.Multiplication:
							if (a instanceof Double || b instanceof Double)
								return a.doubleValue() * b.doubleValue();
							else if (a instanceof Float || b instanceof Float)
								return a.floatValue() * b.floatValue();
							else if (a instanceof Long || b instanceof Long)
								return a.longValue() * b.longValue();
							else
								return a.intValue() * b.intValue();
						case JSymbols.Division:
							if (a instanceof Double || b instanceof Double)
								return a.doubleValue() / b.doubleValue();
							else if (a instanceof Float || b instanceof Float)
								return a.floatValue() / b.floatValue();
							else if (a instanceof Long || b instanceof Long)
								return a.longValue() / b.longValue();
							else
								return a.intValue() / b.intValue();
						default:
							throw new IllegalArgumentException(JSymbols._GetSymbolName(op) + " 不能用于 Number 和 Number 间的运算");
					}
				} else if (bb instanceof String)
					return a.toString() + bb;
				else throw new IllegalArgumentException("没有运算可以适用于 Number 与 " + bb.getClass() + "之间");
			}
		});
		S.add(new JOperator(String.class) {
			@Override
			public Object calc(Object a, Object b, byte op) {
				return (String) a + b;
			}
		});
	}
}